package com.lookme.lmtool.cracker;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSON;
import com.jhlabs.image.ScaleFilter;
import com.lookme.lmtool.utils.*;
import com.lookme.lmtool.cracker.filter.IFilter;
import com.lookme.lmtool.cracker.spliter.ISpliter;
import com.lookme.lmtool.model.SpliterInfo;
import com.lookme.lmtool.model.CharAspect;
import com.lookme.lmtool.model.ItemInfo;
import com.lookme.lmtool.model.ProjectInfo;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 验证码识别对象
 * @author blake
 */
public class Cracker {
    /**
     * 识别验证码
     * @param projectPath 工程存放目录
     * @param itemId 项目ID
     * @param bufferedImage 验证码图像
     * @return 验证结果
     */
    public static String ocr(String projectPath,String itemId, BufferedImage bufferedImage){
        ProjectInfo projectInfo= EnvUtils.loadProject(projectPath);
        for(ItemInfo itemInfo:projectInfo.getItemInfoList()){
            if(itemInfo.getId().equals(itemId)){
                return cracker(itemInfo,bufferedImage,true,true,null);
            }
        }
        return null;
    }
    public static String ocr(InputStream inputStream,String itemId, BufferedImage bufferedImage){
        ProjectInfo projectInfo= EnvUtils.loadProject(inputStream);
        for(ItemInfo itemInfo:projectInfo.getItemInfoList()){
            if(itemInfo.getId().equals(itemId)){
                return cracker(itemInfo,bufferedImage,true,true,null);
            }
        }
        return null;
    }
    /**
     * 识别验证码
     * @param projectInfo 工程对象
     * @param itemId 项目ID
     * @param bufferedImage 验证码图像
     * @return 验证结果
     */
    public static String ocr(ProjectInfo projectInfo,String itemId, BufferedImage bufferedImage){
        for(ItemInfo itemInfo:projectInfo.getItemInfoList()){
            if(itemInfo.getId().equals(itemId)){
                return cracker(itemInfo,bufferedImage,true,true,null);
            }
        }
        return null;
    }
    /**
     * 识别验证码
     * @param item 项目对象
     * @param bufferedImage 验证码图像
     * @return 验证结果
     */
    public static String ocr(ItemInfo item,BufferedImage bufferedImage){
        return cracker(item,bufferedImage,true,true,null);
    }

    public static String cracker(ItemInfo item,BufferedImage bufferedImage,boolean splitImage,boolean ocrChar,CrackerListener listener){
        try {
            //执行图像过滤器操作
            BufferedImage targetBuffedImage = ImageUtils.copyImage(bufferedImage);
            for (IFilter filter : item.getFilterList()) {
                if (filter.isSelected()) {
                    long startTime=System.currentTimeMillis();
                    targetBuffedImage = filter.filter(targetBuffedImage, targetBuffedImage);
                    long endTime=System.currentTimeMillis();
                    filter.setCostTime(endTime-startTime);
                    filter.setImage(targetBuffedImage);
                    targetBuffedImage=ImageUtils.copyImage(targetBuffedImage);
                }
            }
            if(listener!=null){
                listener.filterFinish(targetBuffedImage);
            }
            //将处理过的图像进行分割操作
            if (splitImage&&item.getSpliter() != null) {
                ISpliter spliter = item.getSpliter();
                long startTime=System.currentTimeMillis();
                List<SpliterInfo> splitInfos = spliter.split(targetBuffedImage);
                long endTime=System.currentTimeMillis();
                spliter.setCostTime(endTime-startTime);
                String ocr = "";
                if(ocrChar) {
                    for (SpliterInfo spliterInfo : splitInfos) {
                        BufferedImage showImage = ImageUtils.resizeImage(spliterInfo.getImage(),16,16);
                        spliterInfo.setFeatureImage(showImage);
                        String ocrValue = "";
                        if (item.getCharAspectList() != null) {
                            ocrValue = Cracker.ocr(showImage, item.getCharAspectList());
                        }
                        spliterInfo.setOcrData(ocrValue);
                        ocr += ocrValue;
                    }
                }

                if(listener!=null){
                    listener.splitFinish(splitInfos);
                }

                //调用脚本处理识别结果
                if(ocrChar) {
                    Map<String, Object> params = new HashMap<>();
                    params.put("result", ocr);
                    params.put("HttpUtil", HttpUtil.class);
                    params.put("HttpRequest", HttpRequest.class);
                    params.put("HttpResponse", HttpResponse.class);
                    params.put("sout", System.out);
                    params.put("JSON", JSON.class);
                    params.put("BufferedImage", BufferedImage.class);
                    params.put("ImageIO", ImageIO.class);
                    params.put("ImageUtils", ImageUtils.class);
                    params.put("CalculationUtils", CalculationUtils.class);
                    Object result = JexlUtils.format(item.getOcrScript(), params);
                    if (result == null) {
                        result = ocr;
                    }
                    return result.toString();
                }
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param bufferedImage 验证码图像
     * @param charAspectList 字体特征库
     * @return 识别结果
     */
    public static String ocr(BufferedImage bufferedImage, List<CharAspect> charAspectList){
        String ccode=getCCode(bufferedImage);
        double hc=0;
        String value="0";
        for(CharAspect charAspect:charAspectList){
            double sr= SimilarityUtils.compare(charAspect.getValue(), ccode);
            if(sr>hc){
                hc=sr;
                value=charAspect.getKey();
            }
        }
        return value;
    }


    /**
     * @param ccode 验证码图像特征
     * @param charAspectList 字体特征库
     * @return 识别结果
     */
    public static String ocr(String ccode, List<CharAspect> charAspectList){
        System.out.println(ccode);
        double hc=0;
        String value="0";
        for(CharAspect charAspect:charAspectList){
            double sr= SimilarityUtils.compare(charAspect.getValue(), ccode);
            if(sr>hc){
                hc=sr;
                value=charAspect.getKey();
            }
            System.out.print(charAspect.getKey()+"("+sr+")  "  );
        }
        System.out.println("");
        System.out.println(value+"    "+hc);
        return value;
    }

    /**
     * 获取图像的特征码
     * @param bufferedImage 图像信息
     * @return 返回图像特征码
     */
    public static String getCCode(BufferedImage bufferedImage){
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        String tcode = "";
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                tcode += ImageUtils.isBlack(bufferedImage.getRGB(x, y)) ? "1" : "0";
            }
        }
        return tcode;
    }
}
